package com.my.lock.v3;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.LockSupport;

/**
 * Created by ZhongGang
 * at 2018/7/27 14:37
 */
public class Semaphore {
    private static final Logger LOGGER = LoggerFactory.getLogger(Semaphore.class);

    private AtomicInteger permits;//最大允许同时执行的线程数量
    private Queue<Thread> waiters = new ConcurrentLinkedQueue<>();//等待执行的线程，超过最大允许数量的线程进入此队列
    private int max;//记录最大允许同时执行的线程数量

    public Semaphore(int permits) {
        if (permits <= 0) {
            throw new IllegalArgumentException();
        }

        this.permits = new AtomicInteger(permits);
        max = 0;
        this.max = permits;
    }

    public void acquire() {
        if (this.permits.get() <= 0 || !this.permits.compareAndSet(this.permits.get(), this.permits.get() - 1)) {
            Thread thread = Thread.currentThread();
            this.waiters.add(thread);
            LOGGER.info("park thread: {}, left: {}", thread, this.permits.get());
            LockSupport.park();
            acquire();
        }
    }

    public void release() {
        if (this.permits.get() <= this.max && this.permits.compareAndSet(this.permits.get(), this.permits.get() + 1)) {
            Thread thread = this.waiters.poll();
            if (thread != null) {
                LockSupport.unpark(thread);
                LOGGER.info("unpark thread: {}, left: {}", thread, this.permits.get());
            }
        }
    }

    public AtomicInteger getPermits() {
        return permits;
    }

    public Queue<Thread> getWaiters() {
        return waiters;
    }
}
